﻿define([
    'dojo/_base/declare',
    'dojo/_base/array',
    'dojo/_base/connect',
    'dojo/dom-construct',
    'dojo/dom-style',
    'esri/domUtils',
    'esri/lang',
    'esri/layers/layer',
    'geomap/plugins/kriging.js',
], function (
    declare,
    ArrayUtils,
    ConnectUtils,
    DomConstructUtils,
    DomStyleUtils,
    DomUtils,
    esriLang,
    Layer,
    Kriging
) {
    var KrigingLayer = declare([Layer], {
        constructor: function (options) {
            // this.inherited(arguments, [options]);
            this._map = null; //地图对象
            this._element = null; //图层dom元素
            this._context = null; //图层dom元素
            this._connects = []; //事件集合
            this.graphics = [];
            this.gridWidth = options.gridWidth;
            this.opacity = options.opacity;
            this._krigingIdentifyLayerName = 'krigingIdentify';
            if (
                /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
                    navigator.userAgent
                )
            ) {
                this.gridWidth = options.gridWidth || 2;
            } else {
                this.gridWidth = options.gridWidth || 0.5;
            }
            this.loaded = true;
            this.onLoad(this);
        },

        _setMap: function (map, layersElement) {
            //map.addLayer会触发
            //console.log("_setMap");
            this.layersElement = layersElement;
            this._map = map;

            this._element = DomConstructUtils.create(
                'canvas',
                {
                    width: map.width + 'px',
                    height: map.height + 'px',
                    style: 'position: absolute; left: 0px; top: 0px;opacity:' + this.opacity + ';',
                },
                layersElement
            );
            this._context = this._element.getContext('2d');

            this._connects.push(ConnectUtils.connect(map, 'onPan', this, this._panHandler));
            this._connects.push(
                ConnectUtils.connect(map, 'onZoomStart', this, () => {
                    this._element.style.display = 'none';
                })
            );
            this._connects.push(
                ConnectUtils.connect(map, 'onExtentChange', this, this._extentChangeHandler)
            );
            this._connects.push(ConnectUtils.connect(map, 'onClick', this, this._onClickHandler));
            this._connects.push(
                ConnectUtils.connect(map, 'onMouseMove', this, this._onMouseMoveHandler)
            );

            return this._element;
        },

        _unsetMap: function (map, layersElement) {
            //map.removeLayer会触发
            ArrayUtils.forEach(this._connects, ConnectUtils.disconnect, this);

            this.clear();

            if (this._element) {
                this._element.parentNode.removeChild(this._element);
            }
            if (this._legendElement) {
                this._legendElement.parentNode.removeChild(this._legendElement);
            }
            this._map = null;
            this._element = null;
            this._context = null;
            this._connects = null;
            this.graphics = null;
            this._legendElement = null;
        },
        hide: function () {
            this.visible = false;
            if (this._element) {
                this._element.style.display = 'none';
            }
        },
        show: function () {
            this.visible = true;
            if (this._element) {
                this._element.style.display = 'block';
            }
        },
        _visibilityChangeHandler: function (visible) {
            if (visible) {
                DomUtils.show(this._element);
            } else {
                DomUtils.hide(this._element);
            }
        },

        _panHandler: function (delta, extent) {
            DomStyleUtils.set(this._element, { left: extent.x + 'px', top: extent.y + 'px' });
        },

        _extentChangeHandler: function (extent, delta) {
            DomStyleUtils.set(this._element, { left: '0px', top: '0px' });

            this._refresh();
        },
        _onMouseMoveHandler: function (evt) {
            if (Object.prototype.toString.call(this.options.onMouseMove) == '[object Function]') {
                this.mapUtils._currentClickLayer = this._krigingIdentifyLayerName;
                var point = evt.mapPoint;
                var gridIndex = this.getGridIndex(point.x, point.y);
                this.mapView.removeLayer(this._krigingIdentifyLayerName);
                if (this.grid[gridIndex.x] && this.grid[gridIndex.x][gridIndex.y]) {
                    var data = { x: point.x, y: point.y, z: this.grid[gridIndex.x][gridIndex.y] };

                    evt.graphic = {
                        attributes: data,
                        geometry: point,
                    };
                    this._esriEvent = evt;

                    var e = {
                        mapView: this.mapView,
                        data: data,
                        getLocation: this.getLocation.bind(this),
                    };

                    this.mapView.addLayer('pointLayer', {
                        layerName: this._krigingIdentifyLayerName,
                        data: [{ x: point.x, y: point.y }],
                        symbol: 'common_small_point',
                    });
                    this.options.onMouseMove(e);
                }
            }
        },
        _onClickHandler: function (evt) {
            if (Object.prototype.toString.call(this.clickEvt) == '[object Function]') {
                this.mapUtils._currentClickLayer = this._krigingIdentifyLayerName;
                var point = evt.mapPoint;
                var gridIndex = this.getGridIndex(point.x, point.y);
                this.mapView.removeLayer(this._krigingIdentifyLayerName);
                if (this.grid[gridIndex.x] && this.grid[gridIndex.x][gridIndex.y]) {
                    var data = { x: point.x, y: point.y, z: this.grid[gridIndex.x][gridIndex.y] };

                    evt.graphic = {
                        attributes: data,
                        geometry: point,
                    };
                    this._esriEvent = evt;
                    var e = {
                        mapView: this.mapView,
                        data: data,
                        getLocation: this.getLocation.bind(this),
                    };

                    this.mapView.addLayer('pointLayer', {
                        layerName: this._krigingIdentifyLayerName,
                        data: [{ x: point.x, y: point.y }],
                        symbol: this.clickPointSymbol || 'common_small_point',
                    });
                    this.clickEvt(e);
                }
            }
        },
        removeLayer: function (layer, mapView) {
            mapView.removeLayer(this._krigingIdentifyLayerName);
        },
        hideLayer: function (mapView) {
            $(this._legendElement).hide();
            mapView.hideLayer(this._krigingIdentifyLayerName);
        },
        showLayer: function () {
            $(this._legendElement).show();
        },
        clearCanvas: function () {
            this._context.clearRect(0, 0, this._map.width, this._map.height);
        },
        clear: function () {
            this.clearCanvas();
            this.graphics = [];
        },

        add: function (graphic) {
            this.graphics.push(graphic);

            this._refresh();
        },

        _draw: function (line) {
            var map = this.getMap();
            if (map == null) {
                return;
            }
            this.kriging = new Kriging();
            // Fit data
            var variogram = this.kriging.train(
                this.trainData.t,
                this.trainData.x,
                this.trainData.y,
                'exponential',
                0,
                10
            );
            // Increase width for mobile

            // Plot grid
            // var world2 = convertToMapScreen(map,world);
            this.grid = this.kriging.grid(this.world, variogram, this.gridWidth);

            this._refresh();
        },
        _refresh: function () {
            if (!this.visible) {
                return;
            }
            if (this._map) {
                this.setScale(this._map, this._element);
            }
            if (!this._elementVisible) {
                return;
            }
            var map = this.getMap();
            if (map == null) {
                return;
            }
            var extent = map.extent;

            this._element.width = map.width * this.devicePixelRatio;
            this._element.height = map.height * this.devicePixelRatio;

            this.kriging.plot(
                this._element,
                this.grid,
                [extent.xmin, extent.xmax],
                [extent.ymin, extent.ymax],
                this.colors
            );
        },
        getGridIndex: function (lng, lat) {
            if (!this.kriging.gridExtent) {
                return;
            }
            var gridExtent = this.kriging.gridExtent;
            var xlim = gridExtent.xlim;
            var ylim = gridExtent.ylim;
            var x = Math.ceil((lng - xlim[0]) / this.gridWidth);
            var y = Math.ceil((lat - ylim[0]) / this.gridWidth);
            return { x: x, y: y };
        },
        setScale: function (map, _element) {
            var scale = map.getScale();

            if (this.options && this.options.minScale && this.options.maxScale) {
                if (scale > this.options.minScale || scale < this.options.maxScale) {
                    _element.style.display = 'none';
                    this._elementVisible = false;
                } else {
                    _element.style.display = 'block';
                    this._elementVisible = true;
                }
            } else if (this.options && this.options.minScale > 0) {
                if (scale > this.options.minScale) {
                    _element.style.display = 'none';
                    this._elementVisible = false;
                } else {
                    _element.style.display = 'block';
                    this._elementVisible = true;
                }
            } else if (this.options && this.options.maxScale > 0) {
                if (scale < this.options.maxScale) {
                    _element.style.display = 'none';
                    this._elementVisible = false;
                } else {
                    _element.style.display = 'block';
                    this._elementVisible = true;
                }
            } else {
                _element.style.display = 'block';
                this._elementVisible = true;
            }
        },
    });

    return KrigingLayer;
});
